#include "stdafx.h"
#include "LuaHooker.h"
#include "PatchingUtils.h"


LuaHooker* LuaHooker::_instance = 0;

HMODULE LuaHooker::_luaLib = 0;

int (*LuaHooker::_lua_gettop) (lua_State *) = 0;

void (*LuaHooker::_lua_pushcclosure)(lua_State *, DWORD, DWORD) = 0;

void (*LuaHooker::_lua_setfield)(lua_State *, DWORD, WCHAR*) = 0;

list<void *> LuaHooker::_states;


LuaHooker::LuaHooker()
{
	_instance = this;
	_luaLib = GetModuleHandle(L"lua");
}

HWND LuaHooker::GetManilaWindow()
{
	return FindWindow (L"Manila", 0);
}

LuaHooker* LuaHooker::get_Instance()
{
	if (!_instance)
		_instance = new LuaHooker();
	return _instance;
}

void LuaHooker::Initialize(Logger* logger, TODAYTABSETTINGS* settings)
{
	_logger = logger;
	_settings = settings;
}

/*
** pseudo-indices
*/
#define LUA_REGISTRYINDEX       (-10000)
#define LUA_ENVIRONINDEX        (-10001)
#define LUA_GLOBALSINDEX        (-10002)


int LuaHooker::StaticGetTopSubst(lua_State *L)
{
	if (find(_states.begin(), _states.end(), L) == _states.end())
	{
		_states.push_back(L);
		_lua_pushcclosure(L,  (DWORD)NotifyTodayPageLuaCallback, 0);
		_lua_setfield(L, LUA_GLOBALSINDEX, L"NotifyTodayPage");
	}	

	return _lua_gettop(L);
}


void LuaHooker::Hook(PageChangeCallbackFn pageChangeCallback)
{
	_callback = pageChangeCallback;

	_lua_gettop = (int (__cdecl *)(void *))GetProcAddress(_luaLib, L"lua_gettop");
	_lua_pushcclosure = (void (__cdecl *)(lua_State *,DWORD, DWORD))GetProcAddress(_luaLib, L"lua_pushcclosure");
	_lua_setfield = (void (__cdecl *)(lua_State *,DWORD,WCHAR*))GetProcAddress(_luaLib, L"lua_setfield");
	
	HANDLE hProc = GetProcessByName(L"manila.exe");
	if (!hProc)
	{
		hProc = GetProcessByName(L"manila2.exe");
	}
	
	if (hProc)
	{
		ic_PatchProcImports(hProc, (DWORD)_lua_gettop, (DWORD)StaticGetTopSubst);
	}
}

void LuaHooker::UnHook()
{
	HANDLE hProc = GetProcessByName(L"manila.exe");
	if (!hProc)
	{
		hProc = GetProcessByName(L"manila2.exe");
	}
	
	if (hProc)
	{
		ic_PatchProcImports(hProc, (DWORD)StaticGetTopSubst, (DWORD)_lua_gettop );
	}
}


int LuaHooker::NotifyTodayPageLuaCallback (lua_State* L)
{
	const WCHAR * (*lua_tolstring) (lua_State *, int, int);
	lua_tolstring = (const WCHAR *(__cdecl *)(void *,int, int))GetProcAddress(_luaLib, L"lua_tolstring");

	get_Instance()->_callback(wcsicmp(lua_tolstring(L, 1, 0), L"In") == 0);

	return 0;
}
